﻿using Common;
using DataBase.Models;
using DeviceClientGrain;
using Orleans;
using Orleans.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Server.Impl
{
   /// <summary>
   /// 传输机台，一个工序或者子工序为一组
   /// </summary>
    public class DeviceGroupImpl : Grain, IDeviceGroup
    {
        private readonly IPersistentState<List<DeviceInfo>> cache;
        private readonly ApplicationDBContext db;
         

        public DeviceGroupImpl([PersistentState("deviceGroup", "redisStorage")] IPersistentState<List<DeviceInfo>> persistent, ApplicationDBContext adb)
        {
            this.cache = persistent;
            db = adb;
        }

        public override async Task OnActivateAsync()
        { 
            await base.OnActivateAsync();
            await cache.ReadStateAsync();
            if (cache.State.Count == 0)
            {
                await 重置信息();
            }
        }


       /// <summary>
       /// 修改产线，如果某机台支持多个产线，产线值用逗号分隔
       /// </summary>
       /// <param name="MarkerID">地标</param>
       /// <param name="产线"></param>
       /// <returns></returns>
        public async Task 修改产线(string MarkerID, string 产线)
        {
            var obj = cache.State.Find(x => x.MarkerID == MarkerID);
            if(obj!=null )
            {
                string[] arr = 产线.Split(',');
                obj.Line.Clear();
                foreach(var s in arr)
                {
                    if(int.TryParse(s,out int line))
                    {
                        obj.Line.Add(line);
                    }
                }
                if(obj.Line.Count==0)
                {
                    obj.Line.Add(0);
                } 
                await cache.WriteStateAsync();
            } 
        }

        public async Task 启用禁用(string MarkerID, bool Disable)
        {
            var obj = cache.State.Find(x => x.MarkerID == MarkerID);
            if (obj != null && obj.Disable != Disable)
            {
                obj.Disable = Disable;
                await cache.WriteStateAsync();
            }
        }

        public async Task 更新物料数量(string DeviceID, int InNum, int OutNum)
        {
            var obj = cache.State.Find(x => x.DeviceID == DeviceID);
            if (obj != null )
            {
                if (obj.InNum != InNum || obj.OutNum != OutNum)
                {
                    obj.InNum = InNum;
                    obj.OutNum = OutNum;
                    await cache.WriteStateAsync();
                } 
            }
        }

        public Task<string> 地标对应的机台标识(string MarkerID)
        {
            var obj = cache.State.Find(x => x.MarkerID == MarkerID);
            if (obj == null)
            {
                return Task.FromResult("");
            }
            else
            {
                return Task.FromResult(obj.DeviceID);
            }
        }

        /// <summary>
        /// 这里需要说明一下，该Grain为工序相关性为一组，处于该Grain内的都是同一工序，所以参数上可以省略工序名称
        /// 此外由于车间内布局原因，有些地标是去不了某些机台的。
        /// 产线：-1=无线别要求。
        /// 此外，此处返回的是集合，是否被AGV占用，不在此方法中判断
        /// </summary>
        /// <param name="产线"></param>
        /// <param name="不可去的地标列表"></param>
        /// <returns></returns>
        public Task<List<string>> 选择可用传输机台地标(int 产线 = -1, List<string>? 不可去的地标列表=null)
        {
            var query = cache.State.Where(x => x.Disable == false );
            if (产线 == -1)
            {
                //不需要线别判断，只要满足即可
            }
            else
            {
                //有生产线别要求
                query = query.Where(x => x.Line.Contains(产线));
            }
            if(不可去的地标列表 != null && 不可去的地标列表.Count > 0)
            {
                query = query.Where(x => 不可去的地标列表.Contains(x.MarkerID) == false);
            }

            //优先需要传输的，其次是传输机台料多的
            var list = query.OrderByDescending(x => x.NeedTrans).OrderByDescending(x => x.OutNum).Select(x=>x.MarkerID).ToList();
            return Task.FromResult(list); 
        }

        /// <summary>
        /// 收到机台信号后，设置机台可传输状态
        /// </summary>
        /// <param name="MarkerID"></param>
        /// <param name="Flag"></param>
        /// <returns></returns>
        public async Task 需要传输(string DeviceID, bool Flag)
        {
            var obj = cache.State.Find(x => x.DeviceID == DeviceID);
            if (obj != null && obj.NeedTrans != Flag)
            {
                obj.NeedTrans = Flag;
                await cache.WriteStateAsync();
            }
        }

        public async Task 重置信息()
        {
            //从数据库中读取信息，并更新cache
            string devidegroup = this.GetPrimaryKeyString();
            var 设备 = (from d in db.deviceInfo
                      join m in db.markerInfo on d.DeviceID equals m.DeviceID
                      where d.Group == devidegroup
                      select new
                      {
                          d.DeviceID,
                          d.Disable,
                          m.MarkerID,
                          d.Lines,
                          d.NextGroup,
                      }).ToList();
             

            var tmp = new List<DeviceInfo>();
            设备.ForEach(item =>
            {
                DeviceInfo obj = new DeviceInfo()
                {
                    DeviceID = item.DeviceID,
                    Disable = item.Disable,
                    MarkerID = item.MarkerID,
                    NeedTrans = false,
                    InNum = 0,
                    OutNum = 0,
                    NextGroup = item.NextGroup,
                };
                string[] arr = item.Lines.Split(',');
                foreach (var s in arr)
                {
                    if (int.TryParse(s, out int line))
                    {
                        obj.Line.Add(line);
                    }
                }
                if (obj.Line.Count == 0)
                {
                    obj.Line.Add(0);
                } 
                tmp.Add(obj);
            });
            cache.State = tmp; 
            await cache.WriteStateAsync(); 
        }


 

        public Task<NextProcess> 获取下道工序(string MarkerID)
        {
            var device = cache.State.Find(x => x.MarkerID == MarkerID);
            if (device == null)
            {
                var t = new NextProcess()
                {
                    line = -1,
                    DeviceGroup = "",
                };
                return Task.FromResult(t);
            } 
            var t2 = new NextProcess()
            {
                line = device.Line[0],
                DeviceGroup = device.NextGroup,
            };
            return Task.FromResult(t2);
        }

        public async Task 通知AGV离开(string DeviceID )
        {
            
            var agvSetGrain = GrainFactory.GetGrain<IAgvSet>(0);
            long AGVID= await agvSetGrain.获取传输机台处的AGV(DeviceID);
            if (AGVID > 0)
            {
                var agvGrain=GrainFactory.GetGrain<IAgv>(AGVID);
                _ = agvGrain.允许离开机台();
            } 

        }

        public async Task 通知AGV传输(string DeviceID, TransDirectionEnum type)
        {
            
            var agvSetGrain = GrainFactory.GetGrain<IAgvSet>(0);
            long AGVID = await agvSetGrain.获取传输机台处的AGV(DeviceID);
            if (AGVID > 0)
            {
                var agvGrain = GrainFactory.GetGrain<IAgv>(AGVID);
                switch (type)
                {
                    case TransDirectionEnum.上层传出:
                        _ = agvGrain.单层传输(true,false);
                        break;
                    case TransDirectionEnum.上层传入:
                        _ = agvGrain.单层传输(true, true);
                        break;
                    case TransDirectionEnum.下层传出:
                        _ = agvGrain.单层传输(false, false);
                        break;
                    case TransDirectionEnum.下层传入:
                        _ = agvGrain.单层传输(false, true);
                        break;
                    case TransDirectionEnum.上收下出:
                        _ = agvGrain.一起传输(true);
                        break;
                    case TransDirectionEnum.上出下收:
                        _ = agvGrain.一起传输(false);
                        break;
                } 
            } 
        }
    }

    #region 数据定义
    public class DeviceInfo
    {
        /// <summary>
        /// 机台是否可传输
        /// </summary>
        public bool NeedTrans { get; set; }

        /// <summary>
        /// 产线集合，0为通线
        /// </summary>
        public List<int> Line { get; set; }=new List<int>();
         
        /// <summary>
        /// 地标ID
        /// </summary>
        public string MarkerID { get; set; } = "";


        /// <summary>
        /// 机台ID
        /// </summary>
        public string DeviceID { get; set; } = ""; 

        /// <summary>
        /// 进料口数量
        /// </summary>
        public  int InNum { get; set; }

        /// <summary>
        /// 出料口数量
        /// </summary>
        public  int OutNum { get; set; }


        /// <summary>
        /// 可用状态
        /// </summary>
        public bool Disable { get; set; }  

         


        /// <summary>
        /// 下道工序
        /// </summary>
        public string NextGroup { get; set; } = "";

    }

    #endregion
}
